package com.smartlifev30.baiwei.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

import com.smartlifev30.R;
import com.smartlifev30.utils.DisplayUtils;

/**
 * 环形 滑动选择(类似仪表盘)
 *
 * @author tys
 * @date 2018/8/28
 */
public class PlateView extends View {

    private Paint mTextPaint;
    private Paint mPaint;
    private int mWidth;
    private int mHeight;
    float startAngle;

    /**
     * 环扫过的角度
     */
    float sweepAngle = 225;

    /**
     * 环宽 dp
     */
    private float ringWidth = 30;

    /**
     * 刻度盘上的文字(长度决定分成了几等份)
     */
    private String[] markStrings;

    /**
     * 外圆于空间大小的缩放比例
     */
    private float exCircleRate = 0.9f;

    /**
     * 每一个刻度的度数
     */
    private float mEachAngle;

    /**
     * 刻度文字大小 (sp)
     */
    private float textSize = 14;

    /**
     * 选中位置,数组下标
     */
    private int position;

    /**
     * 刻度线高度 dp
     */
    private int markHeight = 5;

    /**
     * 指示器半径(圆圈)
     */
    private float indicatorRadius;
    private float mPaintWidth = 1;
    private Path path;
    private RectF tempRect;
    private RectF rect;
    private SelectedListen selectedListen;
    private boolean isValidMove;

    public PlateView(Context context) {
        this(context, null);
    }

    public PlateView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public PlateView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaintWidth = DisplayUtils.dp2px(getContext(), mPaintWidth);
        mPaint.setStrokeWidth(mPaintWidth);
        tempRect = new RectF();
        rect = new RectF();
        startAngle = -(sweepAngle / 2) - 90;
        path = new Path();
        ringWidth = DisplayUtils.dp2px(getContext(), ringWidth);
        markHeight = DisplayUtils.dp2px(getContext(), markHeight);
        indicatorRadius = ringWidth / 2 + 8;
        mTextPaint = new TextPaint();
        mTextPaint.setTextAlign(Paint.Align.CENTER);
        mTextPaint.setColor(Color.BLACK);
        mTextPaint.setTextSize(textSize);
        mTextPaint.setTextSize(DisplayUtils.sp2px(getContext(), textSize));
        markStrings = new String[16];
        for (int i = 0; i < markStrings.length; i++) {
            markStrings[i] = String.valueOf(i + 16);
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = mHeight = Math.min(w, h);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int sX = mWidth / 2;
        int sY = mHeight / 2;
        canvas.drawColor(Color.WHITE);
        canvas.translate(sX, sY);
        canvas.scale(exCircleRate, exCircleRate);
        //环
        mEachAngle = sweepAngle / (markStrings.length - 1);
        tempRect.set(-sX, -sY, sX, sY);
        rect.set(tempRect.left + ringWidth, tempRect.top + ringWidth,
                tempRect.right - ringWidth, tempRect.bottom - ringWidth);
        drawRing(canvas, tempRect, rect, mPaint);

        //刻度线,文字
        int save = canvas.save();
        canvas.rotate(startAngle + 90);

        for (int i = 0; i < markStrings.length; i++) {
            String markString = markStrings[i];
            if (i == position) {
                mPaint.setStyle(Paint.Style.FILL);
                mPaint.setColor(Color.WHITE);
                canvas.drawCircle(0, -sY + ringWidth / 2, indicatorRadius, mPaint);
                mPaint.setStyle(Paint.Style.STROKE);
                mPaint.setColor(getResources().getColor(R.color.colorAccent));
                canvas.drawCircle(0, -sY + ringWidth / 2, indicatorRadius, mPaint);
            }
            canvas.drawLine(0, -sY + ringWidth, 0, -sY + ringWidth - markHeight, mPaint);
            canvas.drawText(markString, 0, -sY + ringWidth - (markHeight + 8), mTextPaint);
            canvas.rotate(mEachAngle);
        }
        canvas.restoreToCount(save);
//        path.reset();
//        //中心文字
//        tempRect.left = -60;
//        tempRect.top = -35;
//        tempRect.right = 60;
//        tempRect.bottom = 35;
//        path.addArc(tempRect, -180, 180);
//        mTextPaint.setStyle(Paint.Style.STROKE);
//        canvas.drawTextOnPath(getResources().getString(R.string.app_name), path, 0, 0, mTextPaint);
    }

    private void drawRing(Canvas canvas, RectF exRect, RectF inRect, Paint paint) {
        float positionDegree = mEachAngle * position;
        if (position != 0) {
            paint.setStyle(Paint.Style.FILL);
            paint.setColor(getResources().getColor(R.color.colorAccent));
            canvas.drawArc(exRect, startAngle, positionDegree, true, paint);
            paint.setColor(Color.WHITE);
            canvas.drawArc(inRect, startAngle - 1, positionDegree + 2, true, paint);
        }
        paint.setColor(Color.WHITE);
        paint.setStyle(Paint.Style.STROKE);
        canvas.drawArc(exRect, positionDegree, sweepAngle, false, paint);
        canvas.drawArc(inRect, positionDegree, sweepAngle, false, paint);

        //描边
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(getResources().getColor(R.color.colorAccent));
        canvas.drawArc(exRect, startAngle, sweepAngle, false, paint);
        canvas.drawArc(inRect, startAngle, sweepAngle, false, paint);

        //端点
        int save = canvas.save();
        mPaint.setStyle(Paint.Style.FILL);
        canvas.rotate(startAngle + 90);
        tempRect.left = -ringWidth / 2;
        tempRect.top = -mHeight / 2;
        tempRect.right = ringWidth / 2;
        tempRect.bottom = -mHeight / 2 + ringWidth;
        canvas.drawArc(tempRect, -90, -180, true, mPaint);
        canvas.restoreToCount(save);

        save = canvas.save();
        canvas.rotate(startAngle + 90);
        canvas.rotate(mEachAngle * (markStrings.length - 1));
        if (position == markStrings.length - 1) {
            mPaint.setStyle(Paint.Style.FILL);
            tempRect.left = -ringWidth / 2;
            tempRect.top = -mHeight / 2;
            tempRect.right = ringWidth / 2;
            tempRect.bottom = -mHeight / 2 + ringWidth;
            canvas.drawArc(tempRect, -90, 180, true, mPaint);
        } else {
            mPaint.setStyle(Paint.Style.STROKE);
            tempRect.left = -ringWidth / 2;
            tempRect.top = -mHeight / 2;
            tempRect.right = ringWidth / 2;
            tempRect.bottom = -mHeight / 2 + ringWidth;
            canvas.drawArc(tempRect, -90, 180, false, mPaint);
        }
        canvas.restoreToCount(save);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        final int action = event.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_UP:
                handleUpAction(event.getX(), event.getY());
                isValidMove = false;
                break;
            case MotionEvent.ACTION_MOVE:
                handleMoveAction(event.getX(), event.getY());
                break;
            default:
        }
        return true;
    }

    private void handleMoveAction(float x, float y) {
        float[] point = translate20regional(x, y);
        if (isRingInner(point[0], point[1])) {
            float angle = getAngleDegrees(point[0], point[1]);
            if (angle < sweepAngle + mEachAngle / 2) {
                int round = Math.round(angle / mEachAngle);
                this.position = round;
                isValidMove = true;
                invalidate();
            } else if (angle > 360 - mEachAngle / 2) {
                this.position = 0;
                isValidMove = true;
                invalidate();
            }
        }
    }


    /**
     * up时触发事件
     *
     * @param x
     * @param y
     */
    private void handleUpAction(float x, float y) {
        float[] point = translate20regional(x, y);
        //滑动 并且 进如过有效滑动(在环内,指定角度)
        if (isValidMove) {
            if (isRingInner(point[0], point[1])) {
                float angle = getAngleDegrees(point[0], point[1]);
                if (angle < sweepAngle + mEachAngle / 2) {
                    int round = Math.round(angle / mEachAngle);
                    touchIndex(round);
                } else if (angle > 360 - mEachAngle / 2) {
                    touchIndex(0);
                } else {
                    touchIndex(position);
                }
            } else {
                touchIndex(position);
            }
        } else {
            if (isRingInner(point[0], point[1])) {
                float angle = getAngleDegrees(point[0], point[1]);
                if (angle < sweepAngle + mEachAngle / 2) {
                    int round = Math.round(angle / mEachAngle);
                    touchIndex(round);
                } else if (angle > 360 - mEachAngle / 2) {
                    touchIndex(0);
                }
            }
        }
    }

    /**
     * 选中某个位置
     *
     * @param position
     */
    private void touchIndex(int position) {
        this.position = position;
        invalidate();
        if (selectedListen != null) {
            selectedListen.onSelected(this, position);
        }
    }

    /**
     * 获取角度
     *
     * @param x
     * @param y
     * @return
     */
    private float getAngleDegrees(float x, float y) {
        float h = getHypotenuse(x, y);
        float degrees = (float) Math.toDegrees(Math.acos(x / h));
        float ret = degrees;
        if (y < 0) {
            ret = 360 - degrees;
        }
        return ret;
    }

    /**
     * 是否在环内(包含没有画环区域)
     *
     * @param x
     * @param y
     * @return
     */
    private boolean isRingInner(float x, float y) {
        float h = getHypotenuse(x, y);
        float exWidth = mWidth * exCircleRate / 2.0f;
        float inWidth = exWidth - ringWidth;
        return exWidth >= h && h >= inWidth;
    }

    /**
     * 斜边长
     *
     * @param x
     * @param y
     * @return
     */
    private float getHypotenuse(float x, float y) {
        return (float) Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
    }

    /**
     * 坐标点转换(原点从左上角移动到中点)
     *
     * @param x
     * @param y
     * @return 平移, 旋转后坐标点
     */
    private float[] translate20regional(float x, float y) {
        float[] points = new float[2];
        float x1 = mWidth / 2 - x;
        float y1 = mHeight / 2 - y;
        float rx = (float) (x1 * Math.cos(Math.toRadians(startAngle) + Math.PI) + y1 * Math.sin(Math.toRadians(startAngle) + Math.PI));
        float ry = (float) (y1 * Math.cos(Math.toRadians(startAngle) + Math.PI) - x1 * Math.sin(Math.toRadians(startAngle) + Math.PI));
        points[0] = rx;
        points[1] = ry;
        return points;
    }

    public interface SelectedListen {
        /**
         * 点击选择或者是滑动超出边界时触发
         *
         * @param view
         * @param position 选中的位置，数组下标
         */
        void onSelected(View view, int position);
    }

    public void setSelectedListen(SelectedListen selectedListen) {
        this.selectedListen = selectedListen;
    }
}
